<template>
	<view class="select-container" v-show="show" @touchmove.stop.prevent>
		<view class="mask" :class="activeClass ? 'mask-show' : ''" @tap="onCancel(true)"></view>
		<view class="select-box" :class="activeClass ? 'select-box-show' : ''">
			<view class="header">
				<text class="cancel" @tap="onCancel">{{cancelText}}</text>
				<view class="all" @tap="onAllToggle" v-if="allShow">
					<text :class="isAll ? 'all-active' : ''">全选</text>
				</view>
				<text class="confirm" @tap="onConfirm">{{confirmText}}</text>
			</view>
			<view class="body-warp">
				<scroll-view class="body" scroll-y="true">
					<slot v-if="!data.length" name="tips">
						<view class="empty-tips">暂无数据~</view>
					</slot>
					<view class="select-item"
						:class="[item.disabled ? 'disabled' : '',selectedArr[index] ? 'selected' : '']"
						v-for="(item,index) in data" :key="item[valueName]" @tap="onSelected(index)">
						<view class="label">{{item[labelName]}}</view>
						<text v-show="selectedArr[index]" class="selected-icon">✔</text>
					</view>
				</scroll-view>
			</view>
		</view>
	</view>
</template>
<!-- 多选组件 -->
<script>
	export default {
		model: {
			prop: "value",
			event: ["input"]
		},
		data() {
			return {
				show: false, //是否显示
				activeClass: false, //激活样式状态
				selectedArr: [], //选择对照列表
				selectedArrOld: [] //选择对照列表上一次的数据
			};
		},
		onShow() {
			this.show = this.value;
		},
		computed: {
			// 返回是否全选
			isAll() {
				let wipeDisabledList = this.returnWipeDisabledList();
				if (!wipeDisabledList.length) return false;
				return !wipeDisabledList.includes(false);
			}
		},
		props: {
			// 双向绑定
			value: {
				type: Boolean,
				default: false
			},
			// 取消按钮文字
			cancelText: {
				type: String,
				default: "取消"
			},
			// 确认按钮文字
			confirmText: {
				type: String,
				default: "确认"
			},
			// label对应的key名称
			labelName: {
				type: String,
				default: "label"
			},
			// value对应的key名称
			valueName: {
				type: String,
				default: "value"
			},
			// 是否允许点击遮罩层关闭
			maskCloseAble: {
				type: Boolean,
				default: true
			},
			// 是否显示全选
			allShow: {
				type: Boolean,
				default: true
			},
			// 模式
			mode: {
				type: String,
				default: "multiple"
			},
			// 默认选中值
			defaultSelected: {
				type: Array,
				default: function() {
					return [];
				}
			},
			// 数据源
			data: {
				type: Array,
				required: true,
				default: () => {
					return [];
				}
			}
		},
		watch: {
			async value(newVal) {
				this.show = newVal;
				await this.$nextTick();
				this.activeClass = newVal;
				if (newVal) {
					this.selectedArrOld = JSON.parse(JSON.stringify(this.selectedArr));
				}
			},
			show(newVal) {
				this.$emit("input", newVal);
				this.$emit("change", newVal);
			},
			data: {
				// 设置初始选择对照列表
				handler(list) {
					this.selectedArr = list.map(el => false);
					this.setItemActiveState();
				},
				deep: true,
				immediate: true
			},
			defaultSelected: {
				handler() {
					this.setItemActiveState();
				},
				deep: true,
				immediate: true
			}
		},
		methods: {
			// 设置默认选中通用办法
			setItemActiveState() {
				if (this.data.length && this.defaultSelected.length) {
					this.data.forEach((item, i) => {
						for (let n = 0; n < this.defaultSelected.length; n++) {
							if (
								!item.disabled &&
								item[this.valueName] === this.defaultSelected[n]
							) {
								this.selectedArr.splice(i, 1, true);
								break;
							}
						}
					});
				}
			},
			/**
			 * 选择事件
			 * @index {Number} 点击下标
			 */
			onSelected(index) {
				if (this.data[index].disabled) return;
				let index2Active = this.selectedArr[index];
				this.selectedArr.splice(index, 1, !index2Active);
			},
			// 取消事件
			onCancel(isMask) {
				if (!isMask || this.maskCloseAble) {
					this.show = false;
					this.selectedArr = JSON.parse(JSON.stringify(this.selectedArrOld));
				} else {
					return;
				}
				this.$emit("cancel");
			},
			// 返回去除了disabled状态后的对照列表
			returnWipeDisabledList() {
				let arr = [];
				this.selectedArr.forEach((el, index) => {
					if (!this.data[index].disabled) arr.push(el);
				});
				return arr;
			},
			// 全选/非全选事件
			onAllToggle() {
				let wipeDisabledList = this.returnWipeDisabledList();
				// 如果去除了disabled的对照列表有false的数据，代表未全选
				if (wipeDisabledList.includes(false)) {
					this.selectedArr.forEach((el, index) => {
						if (!this.data[index].disabled)
							this.selectedArr.splice(index, 1, true);
					});
				} else {
					this.selectedArr.forEach((el, index) => {
						if (!this.data[index].disabled)
							el = this.selectedArr.splice(index, 1, false);
					});
				}
			},
			// 确定事件
			onConfirm() {
				this.show = false;
				let selectedData = [];
				this.selectedArr.forEach((el, index) => {
					if (el) {
						selectedData.push(this.data[index]);
					}
				});
				if (this.mode === "multiple") {
					this.$emit("confirm", selectedData);
				} else {
					let backData = selectedData[0] || {};
					this.$emit("confirm", backData);
				}
			}
		}
	};
</script>
<style lang="scss" scoped>
	.select-container {
		width: 100vw;
		height: 100vh;
		position: fixed;
		left: 0;
		top: 0;
		z-index: 999;
		$paddingLR: 26rpx;

		.mask {
			width: 100%;
			height: 100%;
			background-color: $uni-bg-color-mask;
			opacity: 0;
			transition: opacity 0.3s;

			&.mask-show {
				opacity: 1;
			}
		}

		// 选择器内容区域
		.select-box {
			width: 100%;
			position: absolute;
			bottom: 0;
			left: 0;
			transform: translate3d(0rpx, 100%, 0rpx);
			background-color: $uni-bg-color;
			transition: all 0.3s;

			&.select-box-show {
				transform: translateZ(0);
			}

			.header {
				display: flex;
				box-sizing: border-box;
				width: 100%;
				justify-content: space-between;
				border-bottom: 2rpx solid $uni-border-color;
				    line-height: 97rpx;
				    font-size: 34rpx;
				padding: 0 $paddingLR;

				.cancel {
					color: $uni-text-color-grey;
				}

				.all {
					color: $uni-color-success;

					.all-active {
						&::after {
							display: inline-block;
							content: "✔";
							padding-left: 8rpx;
						}
					}
				}

				.confirm {
					color: $uni-color-primary;
				}
			}

			.body-warp {
				width: 100%;
				height: 30vh;
				box-sizing: border-box;
				padding: 20rpx 49rpx;
			}

			.body {
				width: 100%;
				height: 100%;
				overflow-y: auto;

				.empty-tips {
					margin-top: 25%;
					text-align: center;
					font-size: 26rpx;
					color: $uni-color-error;
				}

				.select-item {
					display: flex;
					font-size: 34rpx;
					line-height: 70rpx;
					color: #303133;
					position: relative;
					transition: all 0.3s;

					&.selected {
						color: $uni-color-primary;
					}

					&.disabled {
						color: $uni-text-color-disable;
					}

					>.label {
						flex: 1;
						text-align: center;
					}

					>.selected-icon {
						position: absolute;
						right: 0;
						top: 50%;
						    font-size: 37rpx;
						transform: translateY(-50%);
					}
				}
			}
		}
	}
</style>
